package com.wl.shop.security;

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springside.modules.utils.Encodes;

import com.google.common.base.Objects;
import com.wl.shop.entity.Menu;
import com.wl.shop.entity.Role;
import com.wl.shop.entity.User;
import com.wl.shop.service.SystemService;
import com.wl.shop.utils.LogUtils;
import com.wl.shop.utils.Servlets;
import com.wl.shop.utils.StringUtils;
import com.wl.shop.utils.UserUtils;

public class SystemAuthorizingRealm extends AuthorizingRealm {
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private SystemService systemService;
	
	public void setSystemService(SystemService systemService) {
		this.systemService = systemService;
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// TODO Auto-generated method stub
		logger.info("获取当前已登录的用户");
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		User user = systemService.getUserByLoginName(shiroUser.getloginName());
		if(user != null){
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			List<Menu> list = UserUtils.getMenuList();
			for (Menu menu : list){
				if (StringUtils.isNotBlank(menu.getPermission())){
					// 添加基于Permission的权限信息
					for (String permission : StringUtils.split(menu.getPermission(),",")){
						info.addStringPermission(permission);
					}
				}
			}
			// 添加用户权限
			info.addStringPermission("user");
			
			// 添加用户角色信息
			List<Role> roleList = UserUtils.getRoleList();
			for (Role role : roleList){
				info.addRole(role.getEnname());
			}
			// 更新登录IP和时间
			systemService.updateUserLoginInfo(user);
			// 记录登录日志
			LogUtils.saveLog(Servlets.getRequest(), "系统登录");
			
			return info;
		}else{
			return null;
		}
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		// TODO Auto-generated method stub
		org.apache.shiro.authc.UsernamePasswordToken token = (org.apache.shiro.authc.UsernamePasswordToken)authcToken;
		String username = token.getUsername();
		
		User user = systemService.getUserByLoginName(username);
		if(user == null) {  
            throw new UnknownAccountException();//没找到帐号  
        } 
		if(!user.getLoginFlag()) {  
            throw new LockedAccountException(); //帐号锁定  
        } 
		byte[] salt = Encodes.decodeHex(user.getSalt());
		HttpServletRequest request = WebUtils.getHttpRequest(SecurityUtils.getSubject());
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(  
                new ShiroUser(user.getId(),user.getLoginName(),user.getName(),StringUtils.getRemoteAddr(request)),
                user.getPassword(), //密码  
                ByteSource.Util.bytes(salt),
                getName()  //realm name  
        ); 
		return authenticationInfo;
	}
	
	/**
	 * 设定密码校验的Hash算法与迭代次数
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);
		matcher.setHashIterations(SystemService.HASH_INTERATIONS);
		setCredentialsMatcher(matcher);
	}
	
	/**
	 * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {
		private static final long serialVersionUID = -1373760761780840081L;
		public String id;// 编号
		public String loginName;//登录名
		public String name;//姓名
		public String ip;//用户登录IP

		public ShiroUser(String id, String loginName, String name,String ip) {
			this.id = id;
			this.loginName = loginName;
			this.name = name;
			this.ip=ip;
		}
		
		public String getId() {
			return id;
		}

		public String getloginName() {
			return loginName;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}
		
		/**
		 * 获取SESSIONID
		 */
		public String getSessionid() {
			try{
				return (String) UserUtils.getSession().getId();
			}catch (Exception e) {
				return "";
			}
		}

		/**
		 * 重载hashCode,只计算loginName;
		 */
		@Override
		public int hashCode() {
			return Objects.hashCode(loginName);
		}

		/**
		 * 重载equals,只计算loginName;
		 */
		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			ShiroUser other = (ShiroUser) obj;
			if (loginName == null) {
				if (other.loginName != null) {
					return false;
				}
			} else if (!loginName.equals(other.loginName)) {
				return false;
			}
			return true;
		}
	}

}
